#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <jsoncpp/json/json.h>

#define SPACE " "
#define SPACE_LEN strlen(SPACE)
#define SEP "\r\n"
#define SEP_LEN strlen(SEP)
#define SIZE 1024
#define MYSELF

class Request
{
public:
    Request() {}

    Request(int x, int y, char op)
        : _x(x)
        , _y(y)
        , _op(op)
    {}

    ~Request() {}

    std::string Serialize()
    {
    #ifndef MYSELF        
        std::string str = std::to_string(_x);
        str += SPACE;
        str += _op;
        str += SPACE;
        str += std::to_string(_y);
        return str;
    #else
        Json::Value root;
        root["x"] = _x;
        root["op"] = _op;
        root["y"] = _y;
        Json::FastWriter writer;
        return writer.write(root);
    #endif
    }

    bool Deserialize(std::string& str)
    {
    #ifndef MYSELF
        size_t left = str.find(SPACE);
        if(left == std::string::npos)
            return false;
        size_t right = str.rfind(SPACE);
        if(right == std::string::npos)
            return false;

        if(left + SPACE_LEN >= str.size())
            return false;

        _x = atoi(str.substr(0, left).c_str());
        _y = atoi(str.substr(right + SPACE_LEN).c_str());
        _op = str[left + SPACE_LEN];
    #else
        Json::Value root;
        Json::Reader reader;
        reader.parse(str, root);
        _x = root["x"].asInt();
        _op = root["op"].asInt();
        _y = root["y"].asInt();
        return true;
    #endif
    }

public:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response() {}

    Response(int code, int ret, int x, int y, char op)
        : _code(code)
        , _ret(ret)
        , _x(x)
        , _y(y)
        , _op(op)
    {}

    ~Response() {}

    std::string Serialize()
    {
    #ifndef MYSELF
        std::string str = std::to_string(_code);
        str += SPACE;
        str += std::to_string(_ret);
        return str;
    #else
        Json::Value root;
        root["code"] = _code;
        root["ret"] = _ret;
        root["x"] = _x;
        root["op"] = _op;
        root["y"] = _y;
        Json::FastWriter writer;
        return writer.write(root);
    #endif
    }

    bool Deserialize(const std::string& str)
    {
    #ifndef MYSELF
        size_t pos = str.find(SPACE);
        if(pos == std::string::npos)
            return false;
        _code = atoi(str.substr(0, pos).c_str());
        _ret = atoi(str.substr(pos + SPACE_LEN).c_str());
        return true;
    #else
        Json::Value root;
        Json::Reader reader;
        reader.parse(str, root);
        _code = root["code"].asInt();
        _ret = root["ret"].asInt();
        _x = root["x"].asInt();
        _op = root["op"].asInt();
        _y = root["y"].asInt();
        return true;
    #endif
    }

public:
    int _code;
    int _ret;
    int _x;
    int _y;
    char _op;
};

bool Recv(int sock, std::string* out)
{
    char buffer[SIZE];
    ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
    if(s > 0)
    {
        buffer[s] = '\0';
        *out += buffer;
        return true;
    }
    else if(s == 0)
    {
        std::cout << "Client Quit!" << std::endl;
        return false;
    }
    else
    {
        std::cout << "Recv Error!" << std::endl;
        return false;
    }
}

void Send(int sock, const std::string& str)
{
    int n = send(sock, str.c_str(), str.size(), 0);
    if(n < 0)
        std::cout << "Send Error!" << std::endl;
}

// 去除报头
std::string Decode(std::string& buffer)
{
    size_t pos = buffer.find(SEP);
    if(pos == std::string::npos)
        return "";
    
    int size = atoi(buffer.substr(0, pos).c_str());
    int leftSize = buffer.size() - pos - 2 * SEP_LEN;
    if(leftSize >= size)
    {
        // 至少有一个完整的报文
        buffer.erase(0, pos + SEP_LEN);
        std::string s = buffer.substr(0, size);
        buffer.erase(0, size + SEP_LEN);
        return s;
    }
    else // 没有完整的报文,不进行解析
        return "";
}

// 添加报头
// 有效载荷长度\r\n有效载荷\r\n
std::string Encode(std::string& s)
{
    std::string newPackage = std::to_string(s.size());
    newPackage += SEP;
    newPackage += s;
    newPackage += SEP;
    return newPackage;
}